home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
3D GFX
/
3D GFX.iso
/
amiutils
/
i_l
/
irit5
/
cagd_lib
/
cbsp_int.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-30
|
13KB
|
324 lines
/******************************************************************************
* CBsp-Int.c - Bspline curve interpolation/approximation schemes. *
*******************************************************************************
* Written by Gershon Elber, Feb. 94. *
******************************************************************************/
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "cagd_loc.h"
#include "extra_fn.h"
/*****************************************************************************
* DESCRIPTION: M
* Given a set of points, PtList, computes a Bspline curve of order Order M
* that interpolates or least square approximates the set of points. M
* The size of the control polygon of the resulting Bspline curve defaults M
* to the number of points in PtList (if CrvSize = 0). M
* However, this number is can smaller to yield a least square M
* approximation. M
* The created curve can be parametrized as specified by ParamType. M
* M
* *
* PARAMETERS: M
* PtList: List of points to interpolate/least square approximate. M
* Order: Of interpolating/approximating curve. M
* CrvSize: Number of degrees of freedom (control points) of the M
* interpolating/approximating curve. M
* ParamType: Type of parametrization. M
* *
* RETURN VALUE: M
* CagdCrvStruct *: Constructed interpolating/approximating curve. M
* *
* KEYWORDS: M
* BspCrvInterpPts, interpolation, least square approximation M
*****************************************************************************/
CagdCrvStruct *BspCrvInterpPts(CagdPtStruct *PtList,
int Order,
int CrvSize,
CagdParametrizationType ParamType)
{
int i, NumPts;
CagdPtStruct *Pt;
CagdRType *KV, *PtKnots, *AveKV, *R, *R2, t;
CagdCrvStruct *Crv;
CagdCtlPtStruct
*CtlPt = NULL,
*CtlPtList = NULL;
for (NumPts = 0, Pt = PtList; Pt != NULL; NumPts++, Pt = Pt -> Pnext);
if (CrvSize == 0)
CrvSize = NumPts;
if (NumPts < 3 || NumPts < Order || NumPts < CrvSize || CrvSize < Order)
return NULL;
R = PtKnots = (CagdRType *) IritMalloc(sizeof(CagdRType) * NumPts);
/* Compute parameter values at which the curve will interpolate PtList. */
switch (ParamType) {
case CAGD_CHORD_LEN_PARAM:
*R++ = 0.0;
for (Pt = PtList; Pt -> Pnext != NULL; Pt = Pt -> Pnext, R++)
*R = *(R - 1) + PT_PT_DIST(Pt -> Pt, Pt -> Pnext -> Pt);
for (t = R[-1]; R != PtKnots; *--R /= t);
break;
case CAGD_CENTRIPETAL_PARAM:
*R++ = 0.0;
for (Pt = PtList; Pt -> Pnext != NULL; Pt = Pt -> Pnext, R++)
*R = *(R - 1) + sqrt(PT_PT_DIST(Pt -> Pt, Pt -> Pnext -> Pt));
for (t = R[-1]; R != PtKnots; *--R /= t);
break;
case CAGD_UNIFORM_PARAM:
default:
for (i = 0; i < NumPts; i++)
*R++ = ((RealType) i) / (NumPts - 1);
break;
}
/* Construct the knot vector of the Bspline curve. */
KV = (CagdRType *) IritMalloc(sizeof(CagdRType) * (CrvSize + Order));
AveKV = BspKnotAverage(PtKnots, NumPts, NumPts + Order - CrvSize - 1);
BspKnotAffineTrans(AveKV, CrvSize - Order + 2, PtKnots[0] - AveKV[0],
(PtKnots[NumPts - 1] - PtKnots[0]) /
(AveKV[CrvSize - Order + 1] - AveKV[0]));
for (i = 0, R = KV, R2 = AveKV; i < Order; i++)
*R++ = *R2;
for (i = 0; i < CrvSize - Order; i++)
*R++ = *++R2;
for (i = 0, R2++; i < Order; i++)
*R++ = *R2;
IritFree((VoidPtr) AveKV);
/* Convert to control points in a linear list */
for (Pt = PtList; Pt != NULL; Pt = Pt -> Pnext) {
if (CtlPtList == NULL)
CtlPtList = CtlPt = CagdCtlPtNew(CAGD_PT_E3_TYPE);
else {
CtlPt ->Pnext = CagdCtlPtNew(CAGD_PT_E3_TYPE);
CtlPt = CtlPt -> Pnext;
}
for (i = 0; i < 3; i++)
CtlPt -> Coords[i + 1] = Pt -> Pt[i];
}
Crv = BspCrvInterpolate(CtlPtList, NumPts, PtKnots, KV, CrvSize, Order,
FALSE);
CagdCtlPtFreeList(CtlPtList);
IritFree((VoidPtr *) PtKnots);
IritFree((VoidPtr *) KV);
return Crv;
}
/*****************************************************************************
* DESCRIPTION: M
* Given set of points, PtList, parameter values the curve should interpolate M
* or approximate these points, Params, and the expected knot vector, KV, M
* length Length and order Order of the Bspline curve, computes the Bspline M
* curve's coefficients. M
* All points in PtList are assumed of the same type. M
* If Periodic, Order - 1 more constraints (and DOF's) are added so that M
* the first Order - 1 points are the same as the last Order - 1 points. M
* *
* PARAMETERS: M
* PtList: List of points to interpolate/least square approximate. M
* NumPts: Size of PtList.
* Params: At which to interpolate the points in PtList. M
* KV: Computed knot vector for the constructed curve. M
* Length: Number of degrees of freedom (control points) of the M
* interpolating/approximating curve. M
* Order: Of interpolating/approximating curve. M
* Periodic: If dat a and hence constructed curve should be Periodic. M
* *
* RETURN VALUE: M
* CagdCrvStruct *: Constructed interpolating/approximating curve. M
* *
* KEYWORDS: M
* BspCrvInterpolate, interpolation, least square approximation M
*****************************************************************************/
CagdCrvStruct *BspCrvInterpolate(CagdCtlPtStruct *PtList,
int NumPts,
CagdRType *Params,
CagdRType *KV,
int Length,
int Order,
CagdBType Periodic)
{
int i, j, k,
PerNumPts = NumPts + (Periodic ? Order - 1 : 0);
CagdCtlPtStruct *Pt;
CagdRType *Mat, *InterpPts, *M, *R;
CagdCrvStruct *Crv;
CagdPointType
PtType = PtList -> PtType;
/* Construct the Bspline curve and its knot vector. */
Crv = BspPeriodicCrvNew(Length, Order, Periodic, PtType);
CAGD_GEN_COPY(Crv -> KnotVector, KV,
(CAGD_CRV_PT_LST_LEN(Crv) + Order) * sizeof(CagdRType));
/* Construct the system of equations' matrix. */
M = Mat = (CagdRType *) IritMalloc(sizeof(CagdRType) * Length * PerNumPts);
for (i = 0, R = Params; i < PerNumPts; i++, R++, M += Length) {
int Index;
CagdRType
*Line = BspCrvCoxDeBoorBasis(KV, Order,
Length + (Periodic ? Order - 1 : 0),
*R, &Index);
for (k = 0; k < Length; k++)
M[k] = 0.0;
for (j = Order, k = Index; j > 0; j--, k++)
M[k % Length] = *Line++;
}
/* Compute SVD decompostion for Mat. */
SvdLeastSqr(Mat, NULL, NULL, PerNumPts, Length);
IritFree((VoidPtr *) Mat);
/* Solve for the coefficients of all the coordinates of the curve. */
InterpPts = (CagdRType *) IritMalloc(sizeof(CagdRType) * PerNumPts);
for (i = !CAGD_IS_RATIONAL_PT(PtType);
i <= CAGD_NUM_OF_PT_COORD(PtType);
i++) {
for (Pt = PtList, R = InterpPts, j = PerNumPts;
j > 0;
Pt = Pt -> Pnext, j--)
*R++ = Pt -> Coords[i];
SvdLeastSqr(NULL, Crv -> Points[i], InterpPts, NumPts, Length);
}
IritFree((VoidPtr *) InterpPts);
return Crv;
}
/*****************************************************************************
* DESCRIPTION: M
* Given a set of points, and a curve least square fitting them using the M
* BspCrvInterpPts function, computes an error measure as a the maximal M
* distance between the curve and points (L1 norm). M
* *
* PARAMETERS: M
* Crv: Curve that was fitted to the data set. M
* PtList: The data set. M
* ParamType: Parameter values at with curve should interpolate PtList. M
* *
* RETURN VALUE: M
* CagdRType: Error measured in the L1 norm. M
* *
* KEYWORDS: M
* BspCrvInterpPtsError, error estimation, interpolation, least square M
* approximation M
*****************************************************************************/
CagdRType BspCrvInterpPtsError(CagdCrvStruct *Crv,
CagdPtStruct *PtList,
CagdParametrizationType ParamType)
{
int i, NumPts;
CagdPtStruct *Pt;
CagdRType *PtKnots, *R, t,
MaxDist = 0.0;
for (NumPts = 0, Pt = PtList; Pt != NULL; NumPts++, Pt = Pt -> Pnext);
R = PtKnots = (CagdRType *) IritMalloc(sizeof(CagdRType) * NumPts);
/* Compute parameter values at which the curve will interpolate PtList. */
switch (ParamType) {
case CAGD_CHORD_LEN_PARAM:
*R++ = 0.0;
for (Pt = PtList; Pt -> Pnext != NULL; Pt = Pt -> Pnext, R++)
*R = *(R - 1) + PT_PT_DIST(Pt -> Pt, Pt -> Pnext -> Pt);
for (t = R[-1]; R != PtKnots; *--R /= t);
break;
case CAGD_CENTRIPETAL_PARAM:
*R++ = 0.0;
for (Pt = PtList; Pt -> Pnext != NULL; Pt = Pt -> Pnext, R++)
*R = *(R - 1) + sqrt(PT_PT_DIST(Pt -> Pt, Pt -> Pnext -> Pt));
for (t = R[-1]; R != PtKnots; *--R /= t);
break;
case CAGD_UNIFORM_PARAM:
default:
for (i = 0; i < NumPts; i++)
*R++ = ((RealType) i) / (NumPts - 1);
break;
}
for (i = 0, Pt = PtList; i < NumPts; i++, Pt = Pt -> Pnext) {
CagdRType Dist;
R = CagdCrvEval(Crv, PtKnots[i]);
R = &R[1];
Dist = PT_PT_DIST(R, Pt->Pt);
if (Dist > MaxDist)
MaxDist = Dist;
}
return MaxDist;
}
/*****************************************************************************
* DESCRIPTION: M
* Computes zero and first moments of a curve. M
* *
* PARAMETERS: M
* Crv: To compute zero and first moment. M
* n: Number of samples the curve should be sampled at. M
* Loc: Center of curve as zero moment. M
* Dir: Main direction of curve as first moment. M
* *
* RETURN VALUE: M
* void M
* *
* KEYWORDS: M
* CagdCrvFirstMoments M
*****************************************************************************/
void CagdCrvFirstMoments(CagdCrvStruct *Crv,
int n,
CagdPType Loc,
CagdVType Dir)
{
int i;
CagdRType t, TMin, TMax, Dt, **Points;
CagdPtStruct *Pt,
*PtList = NULL;
CagdCrvStruct *InterpCrv;
if (n < 2)
n = 2;
CagdCrvDomain(Crv, &TMin, &TMax);
t = TMin;
Dt = (TMax - TMin) / (n - 1);
for (i = 0; i < n; i++, t += Dt) {
RealType
*R = CagdCrvEval(Crv, t);
Pt = CagdPtNew();
CagdCoerceToE3(Pt -> Pt, &R, -1, Crv -> PType);
LIST_PUSH(Pt, PtList);
}
InterpCrv = BspCrvInterpPts(PtList, 2, 2, CAGD_UNIFORM_PARAM);
CagdPtFreeList(PtList);
Points = InterpCrv -> Points;
Loc[0] = (Points[1][0] + Points[1][1]) / 2.0;
Loc[1] = (Points[2][0] + Points[2][1]) / 2.0;
Loc[2] = (Points[3][0] + Points[3][1]) / 2.0;
Dir[0] = (Points[1][1] - Points[1][0]);
Dir[1] = (Points[2][1] - Points[2][0]);
Dir[2] = (Points[3][1] - Points[3][0]);
PT_NORMALIZE(Dir);
CagdCrvFree(InterpCrv);
}